package com.rede.didiok.rank.service.impl;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.rede.didiok.common.constant.conf.MessageConf;
import com.rede.didiok.common.constant.conf.RedisConf;
import com.rede.didiok.common.constant.conf.SQLConf;
import com.rede.didiok.common.constant.conf.SysConf;
import com.rede.didiok.common.constant.global.Constants;
import com.rede.didiok.common.domainEvent.EventAction;
import com.rede.didiok.common.dto.rank.RankPraiseRecordDto;
import com.rede.didiok.common.dto.user.UserDto;
import com.rede.didiok.common.enums.PraiseTypeEnum;
import com.rede.didiok.common.enums.ResourceTypeEnum;
import com.rede.didiok.common.enums.StatusEnum;
import com.rede.didiok.common.exception.exceptionType.FeignException;
import com.rede.didiok.common.feign.UserFeignClient;
import com.rede.didiok.common.holder.RequestHolder;
import com.rede.didiok.common.utils.*;
import com.rede.didiok.common.utils.business.DomainEventUtil;
import com.rede.didiok.rank.dao.RankPraiseRecordDao;
import com.rede.didiok.rank.entity.RankPraiseRecordEntity;
import com.rede.didiok.rank.manager.RankCommonManager;
import com.rede.didiok.rank.service.RankMemberService;
import com.rede.didiok.rank.service.RankPraiseRecordService;

@Slf4j
@Service("rankPraiseRecordService")
public class RankPraiseRecordServiceImpl extends ServiceImpl<RankPraiseRecordDao, RankPraiseRecordEntity> implements RankPraiseRecordService {


    @Resource
    RankPraiseRecordDao rankPraiseRecordDao;
    @Resource
    RedisUtil redisUtil;
    //    @Autowired
//    NoticeService noticeService;
    @Resource
    private UserFeignClient userFeignClient;
    @Resource
    private RankMemberService rankMemberService;
    @Resource
    private RankCommonManager rankCommonManager;
    @Resource
    private DomainEventUtil domainEventUtil;

    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        IPage<RankPraiseRecordEntity> page = this.page(
                new Query<RankPraiseRecordEntity>().getPage(params),
                new QueryWrapper<RankPraiseRecordEntity>()
        );

        return new PageUtils(page);
    }

    @Override
    public Map<String, Object> praisedCount(RankPraiseRecordDto userPraiseRecordVO) {
        String userUid = RequestHolder.getUserUid();

        Map<String, Object> map = new HashMap<>(Constants.NUM_FOUR);
        String praiseCountJson = redisUtil.get(RedisConf.RANK_PRAISE_COUNT + RedisConf.SEGMENTATION + userPraiseRecordVO.getResourceUid());
        String treadCountJson = redisUtil.get(RedisConf.RANK_TREAD_COUNT + RedisConf.SEGMENTATION + userPraiseRecordVO.getResourceUid());
        String isPraiseJson = "";
        String isTreadJson = "";
        if (StringUtils.isNotEmpty(userUid)) {
            isPraiseJson = redisUtil.get(RedisConf.IS_USER_RANK_PRAISE + RedisConf.SEGMENTATION + userUid + RedisConf.SEGMENTATION + userPraiseRecordVO.getResourceUid());
            isTreadJson = redisUtil.get(RedisConf.IS_USER_RANK_TREAD + RedisConf.SEGMENTATION + userUid + RedisConf.SEGMENTATION + userPraiseRecordVO.getResourceUid());
            if (StringUtils.isNotEmpty(isPraiseJson)) {
                Boolean isPraise = Boolean.valueOf(isPraiseJson);
                map.put("isPraise", isPraise);
            }
            if (StringUtils.isNotEmpty(isTreadJson)) {
                Boolean isTread = Boolean.valueOf(isTreadJson);
                map.put("isTread", isTread);
            }
        } else {
            map.put("isPraise", false);
            map.put("isTread", false);
        }

        if (StringUtils.isNotEmpty(praiseCountJson)) {
            Integer praiseCount = Integer.valueOf(praiseCountJson);
            map.put("praiseCount", praiseCount);
        } else {
            map.put("praiseCount", 0);
        }
        if (StringUtils.isNotEmpty(treadCountJson)) {
            Integer treadCount = Integer.valueOf(treadCountJson);
            map.put("treadCount", treadCount);
        } else {
            map.put("treadCount", 0);
        }

        // 未登录直接返回false
        if (StringUtils.isNotEmpty(praiseCountJson) &&
                StringUtils.isNotEmpty(treadCountJson) &&
                ((StringUtils.isNotEmpty(isPraiseJson) &&
                        StringUtils.isNotEmpty(isTreadJson)) || StringUtils.isEmpty(userUid))) {
            return map;
        }

        // 类型校验
        Integer praiseCount = 0;
        Integer treadCount = 0;
        Boolean isPraise = false;
        Boolean isTread = false;
        ResourceTypeEnum resourceType = ResourceTypeEnum.getType(userPraiseRecordVO.getResourceType());
        List<RankPraiseRecordEntity> userPraiseRecordList = rankPraiseRecordDao.selectList(new LambdaQueryWrapper<RankPraiseRecordEntity>()
                .eq(RankPraiseRecordEntity::getResourceUid, userPraiseRecordVO.getResourceUid())
                .eq(RankPraiseRecordEntity::getResourceType, resourceType.getType())
                .eq(RankPraiseRecordEntity::getStatus, StatusEnum.ENABLE)
        );

        for (RankPraiseRecordEntity item : userPraiseRecordList) {
            if (PraiseTypeEnum.PRAISE.getType().equals(item.getPraiseType())) {
                if (StringUtils.isNotEmpty(userUid) && userUid.equals(item.getCreateUserUid())) {
                    isPraise = true;
                }
                praiseCount++;
            } else if (PraiseTypeEnum.TREAD.getType().equals(item.getPraiseType())) {
                if (StringUtils.isNotEmpty(userUid) && userUid.equals(item.getCreateUserUid())) {
                    isTread = true;
                }
                treadCount++;
            }
        }
        map.put("praiseCount", praiseCount);
        map.put("isPraise", isPraise);
        map.put("treadCount", treadCount);
        map.put("isTread", isTread);

        // 缓存资源id的点赞数、点踩数
        redisUtil.setEx(RedisConf.RANK_PRAISE_COUNT + RedisConf.SEGMENTATION + userPraiseRecordVO.getResourceUid(), JsonUtils.objectToJson(praiseCount), 10, TimeUnit.MINUTES);
        redisUtil.setEx(RedisConf.RANK_TREAD_COUNT + RedisConf.SEGMENTATION + userPraiseRecordVO.getResourceUid(), JsonUtils.objectToJson(treadCount), 10, TimeUnit.MINUTES);
        if (StringUtils.isNotEmpty(userUid)) {
            redisUtil.setEx(RedisConf.IS_USER_RANK_PRAISE + RedisConf.SEGMENTATION + userUid + RedisConf.SEGMENTATION + userPraiseRecordVO.getResourceUid(), JsonUtils.objectToJson(isPraise), 10, TimeUnit.MINUTES);
            redisUtil.setEx(RedisConf.IS_USER_RANK_TREAD + RedisConf.SEGMENTATION + userUid + RedisConf.SEGMENTATION + userPraiseRecordVO.getResourceUid(), JsonUtils.objectToJson(isTread), 10, TimeUnit.MINUTES);
        }
        return map;
    }

    @Override
    public Integer getPraiseCountByWeek(String userUid) {
        QueryWrapper<RankPraiseRecordEntity> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq(SQLConf.USER_UID, userUid);
        queryWrapper.eq(SQLConf.PRAISE_TYPE, Integer.valueOf(PraiseTypeEnum.PRAISE.getType()));
        queryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
        Date last7Date = DateUtils.getDate(DateUtils.getNowTime(), -7);
        queryWrapper.ge(SQLConf.CREATE_TIME, last7Date);
        return rankPraiseRecordDao.selectCount(queryWrapper);
    }

    @Override
    public Integer getPraiseCount(RankPraiseRecordDto userPraiseRecordVO) {
        QueryWrapper<RankPraiseRecordEntity> queryWrapper = new QueryWrapper<>();
        if (StringUtils.isNotEmpty(userPraiseRecordVO.getCreateUserUid())) {
            queryWrapper.eq(SQLConf.CREATE_USER_UID, userPraiseRecordVO.getCreateUserUid());
        }
        if (StringUtils.isNotEmpty(userPraiseRecordVO.getToUserUid())) {
            queryWrapper.eq(SQLConf.TO_USER_UID, userPraiseRecordVO.getToUserUid());
        }
        if (null != userPraiseRecordVO.getPraiseType()) {
            queryWrapper.eq(SQLConf.PRAISE_TYPE, Integer.valueOf(userPraiseRecordVO.getPraiseType()));
        }
        if (StringUtils.isNotEmpty(userPraiseRecordVO.getResourceUid())) {
            queryWrapper.eq(SQLConf.RESOURCE_UID, userPraiseRecordVO.getResourceUid());
        }
        queryWrapper.eq(SQLConf.STATUS, StatusEnum.ENABLE);
        return rankPraiseRecordDao.selectCount(queryWrapper);
    }

    @Override
    public String refreshPraise() {
        QueryWrapper<RankPraiseRecordEntity> queryWrapper = new QueryWrapper<>();
        Page<RankPraiseRecordEntity> page = new Page<>();
        queryWrapper.isNull("to_user_uid");
        page.setCurrent(1);
        page.setPages(10);
        int count = 0;
        while (true) {
            IPage<RankPraiseRecordEntity> userPraiseRecordPage = rankPraiseRecordDao.selectPage(page, queryWrapper);
            if (userPraiseRecordPage.getRecords().size() == 0) {
                break;
            }
            for (RankPraiseRecordEntity userPraiseRecord : userPraiseRecordPage.getRecords()) {
                ResourceTypeEnum resourceType = ResourceTypeEnum.getType(userPraiseRecord.getResourceType());
                String toUserUid = rankCommonManager.getUserUidByResource(resourceType, userPraiseRecord.getResourceUid());
                userPraiseRecord.setToUserUid(toUserUid);
                userPraiseRecord.updateById();
            }
            count += 1;
            page.setCurrent(count);
            log.info("[refreshPraise] refreshPraise count, count: {}", count);
        }
        return ResultUtil.successWithMessage("刷数成功");
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String praise(RankPraiseRecordDto userPraiseRecordVO) {
        String userUid = RequestHolder.getUserUid();
        // 类型校验
        ResourceTypeEnum resourceType = ResourceTypeEnum.getType(userPraiseRecordVO.getResourceType());
        /**
         * 检索
         * 指定uid 指定资源id 指定资源类型  且为点赞的数据
         * 判断是否已点赞过
         *
         */
        RankPraiseRecordEntity userPraiseRecord = rankPraiseRecordDao.selectOne(
                new LambdaQueryWrapper<RankPraiseRecordEntity>()
                        .eq(RankPraiseRecordEntity::getCreateUserUid, userUid)
                        .eq(RankPraiseRecordEntity::getResourceUid, userPraiseRecordVO.getResourceUid())
                        .eq(RankPraiseRecordEntity::getResourceType, resourceType.getType())
                        .eq(RankPraiseRecordEntity::getStatus, StatusEnum.ENABLE)
                        .last(SysConf.LIMIT_ONE)
        );

        if (userPraiseRecord != null) {
            return ResultUtil.errorWithMessage(MessageConf.YOU_HAVE_BEEN_PRISE);
        }
        RankPraiseRecordEntity newRecord = new RankPraiseRecordEntity();
        newRecord.setCreateUserUid(userUid);
        newRecord.setPraiseType(Integer.valueOf(PraiseTypeEnum.PRAISE.getType()));
        newRecord.setResourceUid(userPraiseRecordVO.getResourceUid());
        newRecord.setResourceType(resourceType.getType());
        newRecord.setStatus(StatusEnum.ENABLE);
        rankPraiseRecordDao.insert(newRecord);

        // 发送点赞成功通知
        domainEventUtil.publishEvent(EventAction.RANK_PRAISE_ADD, newRecord);

        return ResultUtil.successWithMessage(MessageConf.OPERATION_SUCCESS);
    }

    @Override
    public String tread(RankPraiseRecordDto userPraiseRecordVO) {
        String userUid = RequestHolder.getUserUid();
        // 类型校验
        ResourceTypeEnum resourceType = ResourceTypeEnum.getType(userPraiseRecordVO.getResourceType());
        /**
         * 检索
         * 指定uid 指定资源id 指定资源类型  且为点踩的数据
         * 判断是否已点踩过
         *
         */
        RankPraiseRecordEntity userPraiseRecord = rankPraiseRecordDao.selectOne(
                new LambdaQueryWrapper<RankPraiseRecordEntity>()
                        .eq(RankPraiseRecordEntity::getCreateUserUid, userUid)
                        .eq(RankPraiseRecordEntity::getResourceUid, userPraiseRecordVO.getResourceUid())
                        .eq(RankPraiseRecordEntity::getResourceType, resourceType.getType())
                        .eq(RankPraiseRecordEntity::getStatus, StatusEnum.ENABLE)
                        .last(SysConf.LIMIT_ONE)
        );
        if (userPraiseRecord != null) {
            return ResultUtil.errorWithMessage(MessageConf.YOU_HAVE_BEEN_TREADE);
        }
        RankPraiseRecordEntity newRecord = new RankPraiseRecordEntity();
        newRecord.setCreateUserUid(userUid);
        newRecord.setPraiseType(Integer.valueOf(PraiseTypeEnum.TREAD.getType()));
        newRecord.setResourceUid(userPraiseRecordVO.getResourceUid());
        newRecord.setResourceType(resourceType.getType());
        newRecord.setStatus(StatusEnum.ENABLE);
        rankPraiseRecordDao.insert(newRecord);
        // 发送点踩成功通知
        domainEventUtil.publishEvent(EventAction.RANK_TREAD_ADD, newRecord);
        return ResultUtil.successWithMessage(MessageConf.OPERATION_SUCCESS);
    }

    @Override
    public String cancelPraise(RankPraiseRecordDto userPraiseRecordVO) {
        String userUid = RequestHolder.getUserUid();
        // 类型校验
        ResourceTypeEnum resourceType = ResourceTypeEnum.getType(userPraiseRecordVO.getResourceType());
        /**
         * 获取点赞列表
         */
        RankPraiseRecordEntity userPraiseRecord = rankPraiseRecordDao.selectOne(
                new LambdaQueryWrapper<RankPraiseRecordEntity>()
                        .eq(RankPraiseRecordEntity::getPraiseType, Integer.valueOf(PraiseTypeEnum.PRAISE.getType()))
                        .eq(RankPraiseRecordEntity::getResourceUid, userPraiseRecordVO.getResourceUid())
                        .eq(RankPraiseRecordEntity::getResourceType, resourceType.getType())
                        .eq(RankPraiseRecordEntity::getCreateUserUid, userUid)
                        .eq(RankPraiseRecordEntity::getStatus, StatusEnum.ENABLE)
                        .last(SysConf.LIMIT_ONE)
        );
        if (userPraiseRecord != null) {
            userPraiseRecord.setStatus(StatusEnum.DISABLED);
            boolean isSave = userPraiseRecord.updateById();
            // 发送取消点赞成功通知
            if (isSave) {
                domainEventUtil.publishEvent(EventAction.RANK_PRAISE_CANCEL, userPraiseRecord);
            }
        }
        return ResultUtil.successWithMessage(MessageConf.OPERATION_SUCCESS);
    }


    @Override
    public String cancelTread(RankPraiseRecordDto userPraiseRecordVO) {
        String userUid = RequestHolder.getUserUid();
        // 类型校验
        ResourceTypeEnum resourceType = ResourceTypeEnum.getType(userPraiseRecordVO.getResourceType());
        /**
         * 取消点踩
         */
        RankPraiseRecordEntity userPraiseRecord = rankPraiseRecordDao.selectOne(
                new LambdaQueryWrapper<RankPraiseRecordEntity>()
                        .eq(RankPraiseRecordEntity::getPraiseType, Integer.valueOf(PraiseTypeEnum.TREAD.getType()))
                        .eq(RankPraiseRecordEntity::getResourceUid, userPraiseRecordVO.getResourceUid())
                        .eq(RankPraiseRecordEntity::getResourceType, resourceType.getType())
                        .eq(RankPraiseRecordEntity::getCreateUserUid, userUid)
                        .eq(RankPraiseRecordEntity::getStatus, StatusEnum.ENABLE)
                        .last(SysConf.LIMIT_ONE)
        );
        if (userPraiseRecord != null) {
            userPraiseRecord.setStatus(StatusEnum.DISABLED);
            boolean isSave = userPraiseRecord.updateById();
            // 发送取消点赞成功通知
            if (isSave) {
                domainEventUtil.publishEvent(EventAction.RANK_TREAD_CANCEL, userPraiseRecord);
            }
        }
        return ResultUtil.successWithMessage(MessageConf.OPERATION_SUCCESS);
    }

    @Override
    public Boolean hasPraised(RankPraiseRecordDto userPraiseRecordVO) {
        String userUid = RequestHolder.getUserUid();
        // 类型校验
        PraiseTypeEnum praiseType = PraiseTypeEnum.getType(String.valueOf(userPraiseRecordVO.getPraiseType()));
        ResourceTypeEnum resourceType = ResourceTypeEnum.getType(userPraiseRecordVO.getResourceType());
        return rankPraiseRecordDao.selectOne(
                new LambdaQueryWrapper<RankPraiseRecordEntity>()
                        .eq(RankPraiseRecordEntity::getCreateUserUid, userUid)
                        .eq(RankPraiseRecordEntity::getResourceUid, userPraiseRecordVO.getResourceUid())
                        .eq(RankPraiseRecordEntity::getResourceType, resourceType.getType())
                        .eq(RankPraiseRecordEntity::getPraiseType, Integer.valueOf(praiseType.getType()))
                        .eq(RankPraiseRecordEntity::getStatus, StatusEnum.ENABLE)
        ) == null ? false : true;
    }

    @Override
    public List<UserDto> getPraiseList(RankPraiseRecordDto userPraiseRecordVO) {

        // 查找出所有点赞的用户
        List<RankPraiseRecordEntity> userPraiseRecordList = rankPraiseRecordDao.selectList(new QueryWrapper<RankPraiseRecordEntity>().select("DISTINCT `create_user_uid`").lambda()
                .eq(RankPraiseRecordEntity::getResourceUid, userPraiseRecordVO.getResourceUid())
                .eq(RankPraiseRecordEntity::getResourceType, userPraiseRecordVO.getResourceType())
                .eq(RankPraiseRecordEntity::getPraiseType, Integer.valueOf(PraiseTypeEnum.PRAISE.getType()))
                .eq(RankPraiseRecordEntity::getStatus, StatusEnum.ENABLE)
        );

        // 找到用户列表
        Set<String> userUidList = userPraiseRecordList.stream().map(RankPraiseRecordEntity::getCreateUserUid).collect(Collectors.toSet());

        // 判断一下当前登录的用户，是否在点赞列表，如果在则置顶
        String userUid = RequestHolder.getUserUid();
        List<UserDto> userList = new ArrayList<>();
        if (userUidList.size() > 0) {
            List<UserDto> tempUserList = new ArrayList<>();
            R result = userFeignClient.getUserListAndAvatarByIds(userUidList);
            if (result.getCode() == 0) {
                tempUserList = result.getData(new TypeReference<List<UserDto>>(){});
            }else {
                throw new FeignException("feign调用异常（通过ids获取用户列表【携带用户头像和背景图片】）：失败");
            }
            for (UserDto user : tempUserList) {
                if (user.getUid().equals(userUid)) {
                    userList.add(0, user);
                } else {
                    userList.add(user);
                }
            }
        }
        return userList;
    }
}